"""
数据库优化器工具模块

提供各种辅助功能，包括日志记录、数据库连接管理、文件操作等工具函数。
支持模块化设计，便于其他模块调用。
"""

import os
import sys
import logging
from typing import Optional


def get_logger(name: str, 
               log_level: int = logging.INFO,
               log_file: Optional[str] = None
               ) -> logging.Logger:
    """
    获取或创建日志记录器
    
    Args:
        name: 日志记录器名称
        log_level: 日志级别，默认为INFO
        log_file: 可选的日志文件路径
        
    Returns:
        配置好的日志记录器
    """
    # 尝试导入项目的整合日志模块
    try:
        from logging_integration import log_info, log_warning, log_error, log_debug
        
        # 创建一个包装器记录器
        class ProjectLoggerAdapter(logging.LoggerAdapter):
            """项目日志适配器，使用项目已有的日志功能"""
            
            def debug(self, msg, *args, **kwargs):
                if self.logger.isEnabledFor(logging.DEBUG):
                    log_debug(msg)
            
            def info(self, msg, *args, **kwargs):
                if self.logger.isEnabledFor(logging.INFO):
                    log_info(msg)
            
            def warning(self, msg, *args, **kwargs):
                if self.logger.isEnabledFor(logging.WARNING):
                    log_warning(msg)
            
            def error(self, msg, *args, **kwargs):
                if self.logger.isEnabledFor(logging.ERROR):
                    log_error(msg)
        
        # 创建一个基本的logger并包装它
        base_logger = logging.getLogger(name)
        base_logger.setLevel(log_level)
        return ProjectLoggerAdapter(base_logger, {})
        
    except ImportError:
        # 如果无法导入项目日志模块，则创建标准日志记录器
        logger = logging.getLogger(name)
        
        # 如果logger已经配置过，则直接返回
        if logger.handlers:
            return logger
        
        # 设置日志级别
        logger.setLevel(log_level)
        
        # 创建控制台处理器
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setLevel(log_level)
        
        # 创建格式化器
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        console_handler.setFormatter(formatter)
        
        # 添加处理器到logger
        logger.addHandler(console_handler)
        
        # 如果指定了日志文件，则添加文件处理器
        if log_file:
            try:
                os.makedirs(os.path.dirname(os.path.abspath(log_file)), exist_ok=True)
                file_handler = logging.FileHandler(log_file, encoding='utf-8')
                file_handler.setLevel(log_level)
                file_handler.setFormatter(formatter)
                logger.addHandler(file_handler)
            except Exception as e:
                logger.warning(f"无法创建日志文件处理器: {str(e)}")
        
        return logger


def safe_execute_query(cursor, 
                      query: str, 
                      params: tuple = None,
                      max_retries: int = 3,
                      retry_delay: float = 1.0
                      ) -> Optional[list]:
    """
    安全执行SQL查询，支持重试机制
    
    Args:
        cursor: 数据库游标对象
        query: SQL查询语句
        params: 查询参数
        max_retries: 最大重试次数
        retry_delay: 重试间隔（秒）
        
    Returns:
        查询结果，如果执行失败则返回None
    """
    import time
    import sqlite3
    
    retry_count = 0
    
    while retry_count <= max_retries:
        try:
            if params:
                cursor.execute(query, params)
            else:
                cursor.execute(query)
            
            # 如果是SELECT语句，则返回结果
            if query.strip().upper().startswith('SELECT'):
                return cursor.fetchall()
            return []
            
        except sqlite3.OperationalError as e:
            # 对于临时性操作错误，可以重试
            retry_count += 1
            if retry_count > max_retries:
                logger = get_logger(__name__)
                logger.error(f"执行查询失败（已重试{max_retries}次）: {str(e)}")
                return None
            
            # 指数退避策略
            delay = retry_delay * (2 ** (retry_count - 1))
            logger = get_logger(__name__)
            logger.warning(f"执行查询时出错，{delay:.2f}秒后重试 ({retry_count}/{max_retries}): {str(e)}")
            time.sleep(delay)
            
        except Exception as e:
            # 其他类型的错误不重试
            logger = get_logger(__name__)
            logger.error(f"执行查询失败: {str(e)}")
            return None


def get_database_size(db_path: str) -> int:
    """
    获取数据库文件大小
    
    Args:
        db_path: 数据库文件路径
        
    Returns:
        文件大小（字节），如果文件不存在则返回0
    """
    try:
        if os.path.exists(db_path):
            return os.path.getsize(db_path)
        return 0
    except Exception as e:
        logger = get_logger(__name__)
        logger.warning(f"获取数据库大小失败: {str(e)}")
        return 0


def format_size(size_bytes: int) -> str:
    """
    格式化文件大小为人类可读的形式
    
    Args:
        size_bytes: 字节数
        
    Returns:
        格式化后的大小字符串
    """
    for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
        if size_bytes < 1024.0:
            return f"{size_bytes:.2f} {unit}"
        size_bytes /= 1024.0
    return f"{size_bytes:.2f} PB"


def check_database_integrity(connection) -> bool:
    """
    检查数据库完整性
    
    Args:
        connection: 数据库连接对象
        
    Returns:
        数据库是否完整
    """
    try:
        cursor = connection.cursor()
        cursor.execute("PRAGMA integrity_check")
        result = cursor.fetchone()[0]
        cursor.close()
        return result == 'ok'
    except Exception as e:
        logger = get_logger(__name__)
        logger.error(f"检查数据库完整性失败: {str(e)}")
        return False


def get_database_info(connection) -> dict:
    """
    获取数据库基本信息
    
    Args:
        connection: 数据库连接对象
        
    Returns:
        包含数据库信息的字典
    """
    info = {}
    
    try:
        cursor = connection.cursor()
        
        # 获取表数量
        cursor.execute("SELECT COUNT(*) FROM sqlite_master WHERE type='table'")
        info['table_count'] = cursor.fetchone()[0]
        
        # 获取索引数量
        cursor.execute("SELECT COUNT(*) FROM sqlite_master WHERE type='index'")
        info['index_count'] = cursor.fetchone()[0]
        
        # 获取数据库编码
        cursor.execute("PRAGMA encoding")
        info['encoding'] = cursor.fetchone()[0]
        
        # 获取页面大小
        cursor.execute("PRAGMA page_size")
        info['page_size'] = cursor.fetchone()[0]
        
        # 获取缓存大小
        cursor.execute("PRAGMA cache_size")
        info['cache_size'] = cursor.fetchone()[0]
        
        # 获取journal模式
        cursor.execute("PRAGMA journal_mode")
        info['journal_mode'] = cursor.fetchone()[0]
        
        cursor.close()
        
    except Exception as e:
        logger = get_logger(__name__)
        logger.error(f"获取数据库信息失败: {str(e)}")
    
    return info


def ensure_directory_exists(directory: str) -> bool:
    """
    确保目录存在，如果不存在则创建
    
    Args:
        directory: 目录路径
        
    Returns:
        是否成功创建或存在
    """
    try:
        os.makedirs(directory, exist_ok=True)
        return True
    except Exception as e:
        logger = get_logger(__name__)
        logger.error(f"创建目录失败 {directory}: {str(e)}")
        return False


def get_db_path_from_connection(connection) -> Optional[str]:
    """
    尝试从数据库连接获取数据库文件路径
    
    Args:
        connection: SQLite数据库连接对象
        
    Returns:
        数据库文件路径，如果无法获取则返回None
    """
    try:
        # 对于SQLite连接，可以通过游标执行PRAGMA database_list来获取数据库路径
        cursor = connection.cursor()
        cursor.execute("PRAGMA database_list")
        databases = cursor.fetchall()
        cursor.close()
        
        # 查找主数据库（name为'main'）
        for db in databases:
            if db[1] == 'main':
                return db[2]  # db[2]是文件路径
        
        return None
    except Exception as e:
        logger = get_logger(__name__)
        logger.warning(f"获取数据库路径失败: {str(e)}")
        return None


def create_backup_before_optimization(connection, 
                                     backup_dir: Optional[str] = None
                                     ) -> Optional[str]:
    """
    在优化前创建数据库备份
    
    Args:
        connection: 数据库连接对象
        backup_dir: 备份目录，默认为当前目录下的backups文件夹
        
    Returns:
        备份文件路径，如果备份失败则返回None
    """
    import time
    import shutil
    
    # 获取数据库文件路径
    db_path = get_db_path_from_connection(connection)
    if not db_path or not os.path.exists(db_path):
        return None
    
    # 确定备份目录
    if not backup_dir:
        backup_dir = os.path.join(os.getcwd(), 'backups')
    
    # 确保备份目录存在
    if not ensure_directory_exists(backup_dir):
        return None
    
    # 生成备份文件名
    timestamp = time.strftime('%Y%m%d_%H%M%S')
    db_name = os.path.basename(db_path)
    backup_name = f"{os.path.splitext(db_name)[0]}_backup_{timestamp}.db"
    backup_path = os.path.join(backup_dir, backup_name)
    
    # 复制数据库文件
    try:
        # 先关闭事务以确保一致性
        connection.execute("COMMIT")
        # 复制文件
        shutil.copy2(db_path, backup_path)
        
        logger = get_logger(__name__)
        logger.info(f"数据库备份已创建: {backup_path}")
        return backup_path
    except Exception as e:
        logger = get_logger(__name__)
        logger.error(f"创建数据库备份失败: {str(e)}")
        return None